
#ifndef __RIFF_WAVE_WRITER_H__
#define __RIFF_WAVE_WRITER_H__ 1

#include <fstream>
#include <string>
#include <stdint.h>

#include "wave_format_tag.h"

class CRiffWaveWriter
{
public:
	CRiffWaveWriter();
	virtual ~CRiffWaveWriter();

	/**
	 * Create a new RIFF WAVE file. If the wav file already exist and pOverwrite
	 * is false then the methode create will fail. If pOverwrite is true then a
	 * existing wav file will be erased.
	 *
	 * blockAlign = pChannels * ((pBitsPerSample + 7) / 8)
	 */
	bool create(std::string pFilename,
			NWaveFormatTag::EFormatTag pFormatTag,
			uint16_t pChannels,
			uint32_t pSamplesPerSecond,
			uint16_t pBitsPerSample,
			bool pOverwrite);

	/**
	 * Close wav file.
	 *
	 * @return True for success.
	 */
	bool close();

	/**
	 * Save the correct chunk size for the RIFF chunk and data chunk to the wav
	 * file.
	 */
	bool sync();
	
	/**
	 * Get information about the opened wav file.
	 *
	 * @return String which contains the infos.
	 */
	std::string getWaveInfo();

	/**
	 * Return count of samples.
	 * If the wave file has two channels then the value is the count of both
	 * channels.
	 *
	 * @return Count of samples from all channels
	 */
	unsigned int sampleCount();
	
	/**
	 * Get number of channels.
	 * Would be return 1 for mono and 2 for stereo.
	 *
	 * @return Number of channels.
	 */
	unsigned int channels();

	/**
	 * Alignment of one sample.
	 */
	unsigned int bytePerSample();
	
	/**
	 * Write a count of samples into the wav file.
	 * If the wav file has to channels then the samples must be ordered like
	 * CH1, CH2, CH1, CH2, CH1, ... and so on.
	 *
	 * @param pSamples Array for samples which should be written.
	 * @param pCount Count of samples (unit: 1 sample).
	 * @param pCount Count of samples which should be written (unit: 1 sample).
	 *        Array pSamples must has a least pCount elements. One element
	 *        is equal one sample and must have the size of bytePerSample().
	 * @return Count of written samples.
	 */
	unsigned int writeSamples(void* pSamples,
			unsigned int pCount);
	
private:
	std::ofstream mWav;
	uint32_t mRiffChunksize;
	
	struct SFormatChunk
	{
		uint16_t formatTag;
		uint16_t channels;
		uint32_t samplesPerSec;
		uint32_t avgBytesPerSec;
		uint16_t blockAlign;
		uint16_t bitsPerSample;

		// these values are changed by create()
		SFormatChunk()
				:formatTag(1), // for PCM
				channels(2), // mono: 1
				samplesPerSec(44100),
				avgBytesPerSec(176400), // mono: 88200
				blockAlign(4), // mono: 2
				bitsPerSample(16) {}
	} mFormat;
	
	struct SDataChunk
	{
		std::ofstream::pos_type sampleStartPos;
		uint32_t dataChunksize;
		unsigned int bytePerSample;

		SDataChunk()
				:sampleStartPos(0),
				dataChunksize(0),
				bytePerSample(2) {}
	} mData;
	
	bool writeChunks();
};

#endif
